package com.enfi.api.modules.ext.mq.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.*;
import org.springframework.boot.autoconfigure.amqp.RabbitRetryTemplateCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.RetryListener;
import org.springframework.retry.support.RetryTemplate;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;

/**
 * mq 基本配置
 *
 * @author xukk
 * @date 2020/3/9
 */
@Configuration
@Slf4j
public class RabbitMqConfiguration {

    public static final String FANOUT_NOTICE1 = "fanout.notice4";
    public static final String FANOUT_NOTICE_EXCHANGE = "fanout.notice.exchange";

    public static final String FANOUT_FEEDBACK1 = "fanout.feedback1";
    public static final String FANOUT_FEEDBACK_EXCHANGE = "fanout.feedback.exchange";

    public static final String FANOUT_REPORT1 = "fanout.report1";
    public static final String FANOUT_REPORT_EXCHANGE = "fanout.report.exchange";

    public static final String FANOUT_GTASKS1 = "fanout.gtasks1";
    public static final String FANOUT_GTASKS_EXCHANGE = "fanout.gtasks.exchange";


    public static final String FANOUT_WARNING1 = "fanout.warning1";
    public static final String FANOUT_WARNING_EXCHANGE = "fanout.warning.exchange";

    public static final String FANOUT_WORKORDER1 = "fanout.workorder1";
    public static final String FANOUT_WORKORDER_EXCHANGE = "fanout.workorder.exchange";


    public static final String FANOUT_REPLY1 = "fanout.reply1";
    public static final String FANOUT_REPLY_EXCHANGE = "fanout.reply.exchange";

    public static final String FANOUT_SHARE1 = "fanout.share1";
    public static final String FANOUT_SHARE_EXCHANGE = "fanout.share.exchange";

    public static final String FANOUT_DEFAULT1 = "fanout.default1";
    public static final String FANOUT_DEFAULT_EXCHANGE = "fanout.default.exchange";

    public static final String FANOUT_GROUP1 = "fanout.group1";
    public static final String FANOUT_GROUP_EXCHANGE = "fanout.group.exchange";

    public static final String DEAD_QUEUE = "dl.queue1";
    public static final String DEAD_EXCHANGE = "dl.exchange";
    public static final String DEAD_KEY = "ext.dl";


    /**
     * 重试机制日志
     * @return
     */
    @Bean
    public RabbitRetryTemplateCustomizer rabbitRetryTemplateCustomizer() {
        return new RabbitRetryTemplateCustomizer() {
            @Override
            public void customize(Target target, RetryTemplate retryTemplate) {
                retryTemplate.registerListener(new RetryListener() {
                    @Override
                    public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
                        // 第一次重试调用
                        //log.warn("第一次调用");
                        return true;
                    }

                    @Override
                    public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
                        // 最后一次重试会调用
                        log.warn("最后一次重试调用");
                    }

                    @Override
                    public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
                        // 每次重试失败后都会调用
                        log.warn("每次重试失败后都会调用");
                    }
                });
            }
        };
    }


    @PostConstruct
    public void postConstruct() {
    }

    @Bean
    public Queue fanoutNotice1() {
        Map<String, Object> args = new HashMap<>(2);
        //x-dead-letter-exchange    声明  死信交换机
        args.put(DEAD_LETTER_QUEUE_KEY, DEAD_EXCHANGE);
        //x-dead-letter-routing-key    声明 死信路由键
        args.put(DEAD_LETTER_ROUTING_KEY, DEAD_KEY);
        return QueueBuilder.durable(FANOUT_NOTICE1).withArguments(args).build();
    }

    @Bean
    public FanoutExchange fanoutNoticeExchange() {
        return new FanoutExchange(FANOUT_NOTICE_EXCHANGE);
    }

    @Bean
    public Binding fanoutNoticeBinding() {
        return BindingBuilder.bind(fanoutNotice1()).to(fanoutNoticeExchange());
    }


    @Bean
    public Queue fanoutFeedback1() {
        Map<String, Object> args = new HashMap<>(2);
        //x-dead-letter-exchange    声明  死信交换机
        args.put(DEAD_LETTER_QUEUE_KEY, DEAD_EXCHANGE);
        //x-dead-letter-routing-key    声明 死信路由键
        args.put(DEAD_LETTER_ROUTING_KEY, DEAD_KEY);
        return QueueBuilder.durable(FANOUT_FEEDBACK1).withArguments(args).build();
    }

    @Bean
    public FanoutExchange fanoutFeedbackExchange() {
        return new FanoutExchange(FANOUT_FEEDBACK_EXCHANGE);
    }

    @Bean
    public Binding fanoutFeedbackBinding() {
        return BindingBuilder.bind(fanoutFeedback1()).to(fanoutFeedbackExchange());
    }


    @Bean
    public Queue fanoutGtasks1() {
        Map<String, Object> args = new HashMap<>(2);
        //x-dead-letter-exchange    声明  死信交换机
        args.put(DEAD_LETTER_QUEUE_KEY, DEAD_EXCHANGE);
        //x-dead-letter-routing-key    声明 死信路由键
        args.put(DEAD_LETTER_ROUTING_KEY, DEAD_KEY);
        return QueueBuilder.durable(FANOUT_GTASKS1).withArguments(args).build();
    }

    @Bean
    public FanoutExchange fanoutGtasksExchange() {
        return new FanoutExchange(FANOUT_GTASKS_EXCHANGE);
    }

    @Bean
    public Binding fanoutGtasksBinding() {
        return BindingBuilder.bind(fanoutGtasks1()).to(fanoutGtasksExchange());
    }

    @Bean
    public Queue fanoutReport1() {
        Map<String, Object> args = new HashMap<>(2);
        //x-dead-letter-exchange    声明  死信交换机
        args.put(DEAD_LETTER_QUEUE_KEY, DEAD_EXCHANGE);
        //x-dead-letter-routing-key    声明 死信路由键
        args.put(DEAD_LETTER_ROUTING_KEY, DEAD_KEY);
        return QueueBuilder.durable(FANOUT_REPORT1).withArguments(args).build();
    }

    @Bean
    public FanoutExchange fanoutReportExchange() {
        return new FanoutExchange(FANOUT_REPORT_EXCHANGE);
    }

    @Bean
    public Binding fanoutReportBinding() {
        return BindingBuilder.bind(fanoutReport1()).to(fanoutReportExchange());
    }


    @Bean
    public Queue fanoutWarning1() {
        Map<String, Object> args = new HashMap<>(2);
        //x-dead-letter-exchange    声明  死信交换机
        args.put(DEAD_LETTER_QUEUE_KEY, DEAD_EXCHANGE);
        //x-dead-letter-routing-key    声明 死信路由键
        args.put(DEAD_LETTER_ROUTING_KEY, DEAD_KEY);
        return QueueBuilder.durable(FANOUT_WARNING1).withArguments(args).build();
    }

    @Bean
    public FanoutExchange fanoutWarningExchange() {
        return new FanoutExchange(FANOUT_WARNING_EXCHANGE);
    }

    @Bean
    public Binding fanoutWarningBinding() {
        return BindingBuilder.bind(fanoutWarning1()).to(fanoutWarningExchange());
    }



    @Bean
    public Queue fanoutWorkorder1() {
        Map<String, Object> args = new HashMap<>(2);
        //x-dead-letter-exchange    声明  死信交换机
        args.put(DEAD_LETTER_QUEUE_KEY, DEAD_EXCHANGE);
        //x-dead-letter-routing-key    声明 死信路由键
        args.put(DEAD_LETTER_ROUTING_KEY, DEAD_KEY);
        return QueueBuilder.durable(FANOUT_WORKORDER1).withArguments(args).build();
    }

    @Bean
    public FanoutExchange fanoutWorkorderExchange() {
        return new FanoutExchange(FANOUT_WORKORDER_EXCHANGE);
    }

    @Bean
    public Binding fanoutWorkorderBinding() {
        return BindingBuilder.bind(fanoutWorkorder1()).to(fanoutWorkorderExchange());
    }



    @Bean
    public Queue fanoutShare1() {
        Map<String, Object> args = new HashMap<>(2);
        //x-dead-letter-exchange    声明  死信交换机
        args.put(DEAD_LETTER_QUEUE_KEY, DEAD_EXCHANGE);
        //x-dead-letter-routing-key    声明 死信路由键
        args.put(DEAD_LETTER_ROUTING_KEY, DEAD_KEY);
        return QueueBuilder.durable(FANOUT_SHARE1).withArguments(args).build();
    }

    @Bean
    public FanoutExchange fanoutShareExchange() {
        return new FanoutExchange(FANOUT_SHARE_EXCHANGE);
    }

    @Bean
    public Binding fanoutShareBinding() {
        return BindingBuilder.bind(fanoutShare1()).to(fanoutShareExchange());
    }

    @Bean
    public Queue fanoutReply1() {
        Map<String, Object> args = new HashMap<>(2);
        //x-dead-letter-exchange    声明  死信交换机
        args.put(DEAD_LETTER_QUEUE_KEY, DEAD_EXCHANGE);
        //x-dead-letter-routing-key    声明 死信路由键
        args.put(DEAD_LETTER_ROUTING_KEY, DEAD_KEY);
        return QueueBuilder.durable(FANOUT_REPLY1).withArguments(args).build();
    }

    @Bean
    public FanoutExchange fanoutReplyExchange() {
        return new FanoutExchange(FANOUT_REPLY_EXCHANGE);
    }

    @Bean
    public Binding fanoutReplyBinding() {
        return BindingBuilder.bind(fanoutReply1()).to(fanoutReplyExchange());
    }




    @Bean
    public FanoutExchange fanoutGroupExchange() {
        return new FanoutExchange(FANOUT_GROUP_EXCHANGE);
    }

    @Bean
    public Binding fanoutGroupBinding() {
        return BindingBuilder.bind(fanoutGroup1()).to(fanoutGroupExchange());
    }
    @Bean
    public Queue fanoutGroup1() {
        Map<String, Object> args = new HashMap<>(2);
        //x-dead-letter-exchange    声明  死信交换机
        args.put(DEAD_LETTER_QUEUE_KEY, DEAD_EXCHANGE);
        //x-dead-letter-routing-key    声明 死信路由键
        args.put(DEAD_LETTER_ROUTING_KEY, DEAD_KEY);
        return QueueBuilder.durable(FANOUT_GROUP1).withArguments(args).build();
    }

    @Bean
    public FanoutExchange fanoutDefaultExchange() {
        return new FanoutExchange(FANOUT_DEFAULT_EXCHANGE);
    }

    @Bean
    public Binding fanoutDefaultBinding() {
        return BindingBuilder.bind(fanoutDefault1()).to(fanoutDefaultExchange());
    }
    @Bean
    public Queue fanoutDefault1() {
        Map<String, Object> args = new HashMap<>(2);
        //x-dead-letter-exchange    声明  死信交换机
        args.put(DEAD_LETTER_QUEUE_KEY, DEAD_EXCHANGE);
        //x-dead-letter-routing-key    声明 死信路由键
        args.put(DEAD_LETTER_ROUTING_KEY, DEAD_KEY);
        return QueueBuilder.durable(FANOUT_DEFAULT1).withArguments(args).build();
    }
    /**
     * 死信队列 交换机标识符
     */
    private static final String DEAD_LETTER_QUEUE_KEY = "x-dead-letter-exchange";

    /**
     * 死信队列交换机绑定键标识符
     */
    private static final String DEAD_LETTER_ROUTING_KEY = "x-dead-letter-routing-key";


    /**
     * 死信队列跟交换机类型没有关系 不一定为directExchange  不影响该类型交换机的特性.
     *
     * @return the exchange
     */
    @Bean("deadLetterExchange")
    public Exchange deadLetterExchange() {
        return ExchangeBuilder.directExchange(DEAD_EXCHANGE).durable(true).build();
    }

    /**
     * 声明一个死信队列.
     * @return the queue
     */
    @Bean("deadLetterQueue")
    public Queue deadLetterQueue() {
        return QueueBuilder.durable(DEAD_QUEUE).build();
    }


    /**
     * 死信队列绑定到死信交换器上.
     *
     * @return the binding
     */
    @Bean
    public Binding deadLetterBinding() {
        return new Binding(DEAD_QUEUE, Binding.DestinationType.QUEUE, DEAD_EXCHANGE, DEAD_KEY, null);

    }

}
